'use strict';

export default class KunyuAgora {
	/**
	 * @param string appid 声网注册的appid
	 * @param int    uid   用户id
	 * @param string channel 房间号
	 * @param callback 远程用户加入房间处理
	 * @param callback 远程用户离开房间处理
	 * @param string playElementId 默认本地用户播放流的html元素id
	 *
	 */
	constructor(appid, uid, channel, addUserFunc, removeUserFunc, playElementId = 'local_stream') {
		this.rtc = {
			client: null,
			joined: false,
			published: false,
			localStream: null,
			remoteStreams: {},
			params: {},
		}

		this.config = {
			appID: appid,
			cameraId: "",
			cameraResolution: "default",
			channel: channel,
			codec: "h264",
			microphoneId: "",
			mode: "live",
			uid: uid
		}

		this.videos = []
		this.audios = []
		this.resolutions = {
			default: "480p",
			720: "720p",
			1080: "1080p"
		}
		this.modes = ["live", "rtc"]
		this.codes = ["h264", "vp8"]

		this.initDevice(function(videos, audios) {
			this.videos = videos
			this.audios = audios

			this.config.cameraId = videos[0].value
			this.config.cameraResolution = "default"
			this.config.microphoneId = audios[0].value
		})

		this.addUserFunc = addUserFunc
		this.removeUserFunc = removeUserFunc
		
		this.playElementId = playElementId
	}

	initDevice(e) {
		AgoraRTC.getDevices(function(items) {
			items.filter(function(item) {
					return ["audioinput", "videoinput"].indexOf(item.kind) !== -1
				})
				.map(function(item) {
					return {
						name: item.label,
						value: item.deviceId,
						kind: item.kind,
					}
				})
			var videos = []
			var audios = []
			for (var i = 0; i < items.length; i++) {
				var item = items[i]
				if ("videoinput" == item.kind) {
					var name = item.label
					var value = item.deviceId
					if (!name) {
						name = "camera-" + videos.length
					}
					videos.push({
						name: name,
						value: value,
						kind: item.kind
					})
				}
				if ("audioinput" == item.kind) {
					var name = item.label
					var value = item.deviceId
					if (!name) {
						name = "microphone-" + audios.length
					}
					audios.push({
						name: name,
						value: value,
						kind: item.kind
					})
				}
			}
		})
	}

	getDevies() {
		return {
			videos: this.videos,
			audios: this.audios
		}
	}

	/**
	 * 修改频道{房间}
	 * 
	 * @param int channel 
	 */
	setChannel(channel) {
		this.channel = channel
		this.refresh()
	}

	/**
	 * 设置分辨率
	 * 
	 * @param {Object} resolution 分辨率 @see this.resolutions
	 */
	setResolutions(resolution) {
		this.config.cameraResolution = this.resolutions[resolution]
		this.refresh()
	}

	/**
	 * 设置视频编码
	 * 
	 * @param int code 编码 @see this.codes
	 */
	setCodes(code) {
		this.config.code = this.codec
		this.refresh()
	}

	/**
	 * 设置播放模式
	 * 
	 * @param {Object} mode 播放模式
	 */
	setMode(mode) {
		this.config.mode = this.modes[mode]
	}

	join() {
		var rtc = this.rtc
		var _this = this
		var option = this.config
		if (rtc.joined) {
			console.log("Your already joined")
			return;
		}

		rtc.client = AgoraRTC.createClient({
			mode: option.mode,
			codec: option.codec
		})

		rtc.params = option

		// handle AgoraRTC client event
		this.streamHandle(rtc)

		// init client
		rtc.client.init(option.appID, function() {
			console.log("init success")

			rtc.client.join(option.token ? option.token : null, option.channel, option.uid ? +option.uid : null, function(
				uid) {
				console.log("join channel: " + option.channel + " success, uid: " + uid)
				console.log("join channel: " + option.channel + " success, uid: " + uid)
				rtc.joined = true

				rtc.params.uid = uid

				console.log('option')
				console.log(option)

				// create local stream
				rtc.localStream = AgoraRTC.createStream({
					streamID: rtc.params.uid,
					audio: true,
					video: true,
					screen: false,
					microphoneId: option.microphoneId,
					cameraId: option.cameraId
				})

				// initialize local stream. Callback function executed after intitialization is done
				rtc.localStream.init(function() {
					console.log("init local stream success")
					// play stream with html element id "local_stream"
					console.log(rtc.localStream)
					rtc.localStream.play(_this.playElementId)

					// publish local stream
					_this.publish(rtc)
				}, function(err) {
					console.log("stream init failed, please open console see more detail")
					console.error("init local stream failed ", err)
				})
			}, function(err) {
				console.log("client join failed, please open console see more detail")
				console.error("client join failed", err)
			})
		}, (err) => {
			console.log("client init failed, please open console see more detail")
			console.error(err)
		})
	}

	unpublish() {
		var rtc = this.rtc
		if (!rtc.client) {
			console.log("Please Join Room First")
			return
		}
		if (!rtc.published) {
			console.log("Your didn't publish")
			return
		}
		var oldState = rtc.published
		rtc.client.unpublish(rtc.localStream, function(err) {
			rtc.published = oldState
			console.log("unpublish failed")
			console.log("unpublish failed")
			console.error(err)
		})
		console.log("unpublish")
		rtc.published = false
	}

	publish() {
		var rtc = this.rtc
		if (!rtc.client) {
			console.log("Please Join Room First")
			return
		}
		if (rtc.published) {
			console.log("Your already published")
			return
		}
		var oldState = rtc.published

		// publish localStream
		rtc.client.publish(rtc.localStream, function(err) {
			rtc.published = oldState
			console.log("publish failed")
			console.log("publish failed")
			console.error(err)
		})
		console.log("publish")
		rtc.published = true
	}

	leave() {
		var rtc = this.rtc
		if (!rtc.client) {
			console.log("Please Join First!")
			return
		}
		if (!rtc.joined) {
			console.log("You are not in channel")
			return
		}
		/**
		 * Leaves an AgoraRTC Channel
		 * This method enables a user to leave a channel.
		 **/
		rtc.client.leave(function() {
			var _this = this
			// stop stream
			if (rtc.localStream.isPlaying()) {
				rtc.localStream.stop()
			}
			// close stream
			rtc.localStream.close()
			for (let [key, value] of Object.entries(rtc.remoteStreams)) {
				if (value.isPlaying()) {
					value.close()
					_this.removeUserFunc(id)
				}
			}
			rtc.localStream = null
			rtc.remoteStreams = []
			rtc.client = null
			console.log("client leaves channel success")
			rtc.published = false
			rtc.joined = false
			console.log("leave success")
		}, function(err) {
			console.log("channel leave failed")
			console.log("leave success")
			console.error(err)
		})
	}

	streamHandle() {
		var _this = this
		var rtc = this.rtc
		rtc.client.on("error", (err) => {
			console.log(err)
		})
		// Occurs when the peer user leaves the channel; for example, the peer user calls Client.leave.
		rtc.client.on("peer-leave", function(evt) {
			var id = evt.uid;
			console.log("id", evt)
			//let streams = rtc.remoteStreams.filter(e => id !== e.getId())
			let peerStream = rtc.remoteStreams[id]
			delete(rtc.remoteStreams[id])
			if (peerStream && peerStream.isPlaying()) {
				peerStream.stop()
			}
			if (id !== rtc.params.uid) {
				_this.removeUserFunc(id)
			}
			console.log("peer leave")
			console.log("peer-leave", id)
		})
		// Occurs when the local stream is published.
		rtc.client.on("stream-published", function(evt) {
			console.log("stream published success")
			console.log("stream-published")
		})
		// Occurs when the remote stream is added.
		rtc.client.on("stream-added", function(evt) {

			var remoteStream = evt.stream
			var id = remoteStream.getId()
			console.log("stream-added uid: " + id)
			if (id !== rtc.params.uid) {
				rtc.client.subscribe(remoteStream, function(err) {
					console.log("stream subscribe failed", err)
				})
			}
			console.log("stream-added remote-uid: ", id)
		})
		// Occurs when a user subscribes to a remote stream.
		rtc.client.on("stream-subscribed", function(evt) {
			var remoteStream = evt.stream
			var id = remoteStream.getId()
			rtc.remoteStreams[id] = remoteStream
			_this.addUserFunc(id, remoteStream)
			console.log("stream-subscribed remote-uid: " + id)
			console.log("stream-subscribed remote-uid: ", id)
		})

		rtc.client.on("stream-removed", function(evt) {
			var remoteStream = evt.stream
			var id = remoteStream.getId()
			console.log("stream-removed uid: " + id)
			if (remoteStream.isPlaying()) {
				remoteStream.stop()
			}
			delete(rtc.remoteStreams[id])
			_this.removeUserFunc(id)
			console.log("stream-removed remote-uid: ", id)
		})
		rtc.client.on("onTokenPrivilegeWillExpire", function() {
			// After requesting a new token
			// rtc.client.renewToken(token);
			//console.log("onTokenPrivilegeWillExpire")
			//console.log("onTokenPrivilegeWillExpire")
		})
		rtc.client.on("onTokenPrivilegeDidExpire", function() {
			//console.log("onTokenPrivilegeDidExpire")
			//console.log("onTokenPrivilegeDidExpire")
		})

	}

	refresh() {
		this.leave()
		this.join()
	}
}
